/*
 * bitmap.h
 *
 *  Created on: May 26, 2011
 *      Author: Mo
 */

#ifndef BITMAP_H_
#define BITMAP_H_


#endif /* BITMAP_H_ */
#define red "red"
#define green "green"
#define blue "blue"
#define average "average"
#include <math.h>
#include <sstream>


/*
 * Windows Bitmap File Loader
 * Version 1.2.3 (20110407)
 *
 * Supported Formats: 1, 4, 8, 16, 24, 32 Bit Images
 * Alpha Bitmaps are also supported.
 * Supported compression types: RLE 8, BITFIELDS
 *
 * Created by: Benjamin Kalytta, 2006 - 2011
 *
 * Licence: Free to use, URL to my source and my name is required in your source code.
 *
 * Source can be found at http://www.kalytta.com/bitmap.h
 */

#ifndef BITMAP_H
#define BITMAP_H

#include <iostream>
#include <fstream>
#include <string>
#include <assert.h>
using namespace std;

#ifndef __LITTLE_ENDIAN__
	#ifndef __BIG_ENDIAN__
		#define __LITTLE_ENDIAN__
	#endif
#endif

#ifdef __LITTLE_ENDIAN__
	#define BITMAP_SIGNATURE 0x4d42
#else
	#define BITMAP_SIGNATURE 0x424d
#endif

#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
	typedef unsigned __int32 uint32_t;
	typedef unsigned __int16 uint16_t;
	typedef unsigned __int8 uint8_t;
	typedef __int32 int32_t;
#elif defined(__GNUC__) || defined(__CYGWIN__) || defined(__MWERKS__) || defined(__WATCOMC__) || defined(__PGI) || defined(__LCC__)
	#include <stdint.h>
#else
	typedef unsigned int uint32_t;
	typedef unsigned short int uint16_t;
	typedef unsigned char uint8_t;
	typedef int int32_t;
#endif

#pragma pack(push, 1)

typedef struct _BITMAP_FILEHEADER {
	uint16_t Signature;
	uint32_t Size;
	uint32_t Reserved;
	uint32_t BitsOffset;
} BITMAP_FILEHEADER;

#define BITMAP_FILEHEADER_SIZE 14

typedef struct _BITMAP_HEADER {
	uint32_t HeaderSize;
	int32_t Width;
	int32_t Height;
	uint16_t Planes;
	uint16_t BitCount;
	uint32_t Compression;
	uint32_t SizeImage;
	int32_t PelsPerMeterX;
	int32_t PelsPerMeterY;
	uint32_t ClrUsed;
	uint32_t ClrImportant;
	uint32_t RedMask;
	uint32_t GreenMask;
	uint32_t BlueMask;
	uint32_t AlphaMask;
	uint32_t CsType;
	uint32_t Endpoints[9]; // see http://msdn2.microsoft.com/en-us/library/ms536569.aspx
	uint32_t GammaRed;
	uint32_t GammaGreen;
	uint32_t GammaBlue;
} BITMAP_HEADER;

typedef struct _RGBA {
	uint8_t Red;
	uint8_t Green;
	uint8_t Blue;
	uint8_t Alpha;
} RGBA;

typedef struct _BGRA {
	uint8_t Blue;
	uint8_t Green;
	uint8_t Red;
	uint8_t Alpha;
} BGRA;

#pragma pack(pop)

string int2Str(int number);
//{
//	stringstream ss;//create a stringstream
//	ss << number;//add number to the stream
//	return ss.str();//return a string with the contents of the stream
//}


class CBitmap {
private:
	BITMAP_FILEHEADER m_BitmapFileHeader;
	BITMAP_HEADER m_BitmapHeader;
	RGBA *m_BitmapData;
	unsigned int m_BitmapSize;

	// Masks and bit counts shouldn't exceed 32 Bits
public:
	class CColor {
public:
		static inline unsigned int BitCountByMask(unsigned int Mask) {
			unsigned int BitCount = 0;
			while (Mask) {
				Mask &= Mask - 1;
				BitCount++;
			}
			return BitCount;
		}

		static inline unsigned int BitPositionByMask(unsigned int Mask) {
			return BitCountByMask((Mask & (~Mask + 1)) - 1);
		}

		static inline unsigned int ComponentByMask(unsigned int Color, unsigned int Mask) {
			unsigned int Component = Color & Mask;
			return Component >> BitPositionByMask(Mask);
		}

		static inline unsigned int BitCountToMask(unsigned int BitCount) {
			return (BitCount == 32) ? 0xFFFFFFFF : (1 << BitCount) - 1;
		}

		static unsigned int Convert(unsigned int Color, unsigned int FromBitCount, unsigned int ToBitCount) {
			if (ToBitCount < FromBitCount) {
				Color >>= (FromBitCount - ToBitCount);
			} else {
				Color <<= (ToBitCount - FromBitCount);
				if (Color > 0) {
					Color |= BitCountToMask(ToBitCount - FromBitCount);
				}
			}
			return Color;
		}
	};

public:

	CBitmap(string Filename) : m_BitmapData(0), m_BitmapSize(0) {
		Load(Filename);
	}

	CBitmap() : m_BitmapData(0), m_BitmapSize(0)  {
		Dispose();
	}

	CBitmap(char* Filename) : m_BitmapData(0), m_BitmapSize(0) {
		Load(Filename);
	}

	~CBitmap() {
		Dispose();
	}

	void Dispose() {
		if (m_BitmapData) {
			delete[] m_BitmapData;
			m_BitmapData = 0;
		}
		memset(&m_BitmapFileHeader, 0, sizeof(m_BitmapFileHeader));
		memset(&m_BitmapHeader, 0, sizeof(m_BitmapHeader));
	}

	/* Load specified Bitmap and stores it as RGBA in an internal buffer */
	bool Load (string Filename)
	{
		char* charName = (char*) Filename.data();
		return Load (charName);
	}
	bool Load(char *Filename) {
		std::ifstream file(Filename, std::ios::binary | std::ios::in);

		if (file.is_open() == false) {
			return false;
		}

		Dispose();

		file.read((char*) &m_BitmapFileHeader, BITMAP_FILEHEADER_SIZE);
		if (m_BitmapFileHeader.Signature != BITMAP_SIGNATURE) {
			return false;
		}

		file.read((char*) &m_BitmapHeader, sizeof(BITMAP_HEADER));

		/* Load Color Table */

		file.seekg(BITMAP_FILEHEADER_SIZE + m_BitmapHeader.HeaderSize, std::ios::beg);

		unsigned int ColorTableSize = 0;

		if (m_BitmapHeader.BitCount == 1) {
			ColorTableSize = 2;
		} else if (m_BitmapHeader.BitCount == 4) {
			ColorTableSize = 16;
		} else if (m_BitmapHeader.BitCount == 8) {
			ColorTableSize = 256;
		}

		BGRA* ColorTable = new BGRA[ColorTableSize];

		file.read((char*) ColorTable, sizeof(BGRA) * ColorTableSize);

		/* ... Color Table for 16 Images are not supported yet */

		m_BitmapSize = GetWidth() * GetHeight();
		m_BitmapData = new RGBA[m_BitmapSize];

		unsigned int LineWidth = ((GetWidth() * GetBitCount() / 8) + 3) & ~3;
		uint8_t *Line = new uint8_t[LineWidth];

		file.seekg(m_BitmapFileHeader.BitsOffset, std::ios::beg);

		int Index = 0;

		if (m_BitmapHeader.Compression == 0) {
			for (unsigned int i = 0; i < GetHeight(); i++) {
				file.read((char*) Line, LineWidth);

				uint8_t *LinePtr = Line;

				for (unsigned int j = 0; j < GetWidth(); j++) {
					if (m_BitmapHeader.BitCount == 1) {
						uint32_t Color = *((uint8_t*) LinePtr);
						for (int k = 0; k < 8; k++) {
							m_BitmapData[Index].Red = ColorTable[Color & 0x80 ? 1 : 0].Red;
							m_BitmapData[Index].Green = ColorTable[Color & 0x80 ? 1 : 0].Green;
							m_BitmapData[Index].Blue = ColorTable[Color & 0x80 ? 1 : 0].Blue;
							m_BitmapData[Index].Alpha = ColorTable[Color & 0x80 ? 1 : 0].Alpha;
							Index++;
							Color <<= 1;
						}
						LinePtr++;
						j += 7;
					} else if (m_BitmapHeader.BitCount == 4) {
						uint32_t Color = *((uint8_t*) LinePtr);
						m_BitmapData[Index].Red = ColorTable[(Color >> 4) & 0x0f].Red;
						m_BitmapData[Index].Green = ColorTable[(Color >> 4) & 0x0f].Green;
						m_BitmapData[Index].Blue = ColorTable[(Color >> 4) & 0x0f].Blue;
						m_BitmapData[Index].Alpha = ColorTable[(Color >> 4) & 0x0f].Alpha;
						Index++;
						m_BitmapData[Index].Red = ColorTable[Color & 0x0f].Red;
						m_BitmapData[Index].Green = ColorTable[Color & 0x0f].Green;
						m_BitmapData[Index].Blue = ColorTable[Color & 0x0f].Blue;
						m_BitmapData[Index].Alpha = ColorTable[Color & 0x0f].Alpha;
						Index++;
						LinePtr++;
						j++;
					} else if (m_BitmapHeader.BitCount == 8) {
						uint32_t Color = *((uint8_t*) LinePtr);
						m_BitmapData[Index].Red = ColorTable[Color].Red;
						m_BitmapData[Index].Green = ColorTable[Color].Green;
						m_BitmapData[Index].Blue = ColorTable[Color].Blue;
						m_BitmapData[Index].Alpha = ColorTable[Color].Alpha;
						Index++;
						LinePtr++;
					} else if (m_BitmapHeader.BitCount == 16) {
						uint32_t Color = *((uint16_t*) LinePtr);
						m_BitmapData[Index].Red = ((Color >> 10) & 0x1f) << 3;
						m_BitmapData[Index].Green = ((Color >> 5) & 0x1f) << 3;
						m_BitmapData[Index].Blue = (Color & 0x1f) << 3;
						m_BitmapData[Index].Alpha = 255;
						Index++;
						LinePtr += 2;
					} else if (m_BitmapHeader.BitCount == 24) {
						uint32_t Color = *((uint32_t*) LinePtr);
						m_BitmapData[Index].Blue = Color & 0xff;
						m_BitmapData[Index].Green = (Color >> 8) & 0xff;
						m_BitmapData[Index].Red = (Color >> 16) & 0xff;
						m_BitmapData[Index].Alpha = 255;
						Index++;
						LinePtr += 3;
					} else if (m_BitmapHeader.BitCount == 32) {
						uint32_t Color = *((uint32_t*) LinePtr);
						m_BitmapData[Index].Blue = Color & 0xff;
						m_BitmapData[Index].Green = (Color >> 8) & 0xff;
						m_BitmapData[Index].Red = (Color >> 16) & 0xff;
						m_BitmapData[Index].Alpha = Color >> 24;
						Index++;
						LinePtr += 4;
					}
				}
			}
		} else if (m_BitmapHeader.Compression == 1) { // RLE 8
			uint8_t Count = 0;
			uint8_t ColorIndex = 0;
			int x = 0, y = 0;

			while (file.eof() == false) {
				file.read((char*) &Count, sizeof(uint8_t));
				file.read((char*) &ColorIndex, sizeof(uint8_t));

				if (Count > 0) {
					Index = x + y * GetWidth();
					for (int k = 0; k < Count; k++) {
						m_BitmapData[Index + k].Red = ColorTable[ColorIndex].Red;
						m_BitmapData[Index + k].Green = ColorTable[ColorIndex].Green;
						m_BitmapData[Index + k].Blue = ColorTable[ColorIndex].Blue;
						m_BitmapData[Index + k].Alpha = ColorTable[ColorIndex].Alpha;
					}
					x += Count;
				} else if (Count == 0) {
					int Flag = ColorIndex;
					if (Flag == 0) {
						x = 0;
						y++;
					} else if (Flag == 1) {
						break;
					} else if (Flag == 2) {
						char rx = 0;
						char ry = 0;
						file.read((char*) &rx, sizeof(char));
						file.read((char*) &ry, sizeof(char));
						x += rx;
						y += ry;
					} else {
						Count = Flag;
						Index = x + y * GetWidth();
						for (int k = 0; k < Count; k++) {
							file.read((char*) &ColorIndex, sizeof(uint8_t));
							m_BitmapData[Index + k].Red = ColorTable[ColorIndex].Red;
							m_BitmapData[Index + k].Green = ColorTable[ColorIndex].Green;
							m_BitmapData[Index + k].Blue = ColorTable[ColorIndex].Blue;
							m_BitmapData[Index + k].Alpha = ColorTable[ColorIndex].Alpha;
						}
						x += Count;
						// Attention: Current Microsoft STL implementation seems to be buggy, tellg() always returns 0.
						if (file.tellg() & 1) {
							file.seekg(1, std::ios::cur);
						}
					}
				}
			}
		} else if (m_BitmapHeader.Compression == 2) { // RLE 4
			/* RLE 4 is not supported */
		} else if (m_BitmapHeader.Compression == 3) { // BITFIELDS

			/* We assumes that mask of each color component can be in any order */

			uint32_t BitCountRed = CColor::BitCountByMask(m_BitmapHeader.RedMask);
			uint32_t BitCountGreen = CColor::BitCountByMask(m_BitmapHeader.GreenMask);
			uint32_t BitCountBlue = CColor::BitCountByMask(m_BitmapHeader.BlueMask);
			uint32_t BitCountAlpha = CColor::BitCountByMask(m_BitmapHeader.AlphaMask);

			for (unsigned int i = 0; i < GetHeight(); i++) {
				file.read((char*) Line, LineWidth);

				uint8_t *LinePtr = Line;

				for (unsigned int j = 0; j < GetWidth(); j++) {

					uint32_t Color = 0;

					if (m_BitmapHeader.BitCount == 16) {
						Color = *((uint16_t*) LinePtr);
						LinePtr += 2;
					} else if (m_BitmapHeader.BitCount == 32) {
						Color = *((uint32_t*) LinePtr);
						LinePtr += 4;
					} else {
						// Other formats are not valid
					}
					m_BitmapData[Index].Red = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.RedMask), BitCountRed, 8);
					m_BitmapData[Index].Green = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.GreenMask), BitCountGreen, 8);
					m_BitmapData[Index].Blue = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.BlueMask), BitCountBlue, 8);
					m_BitmapData[Index].Alpha = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.AlphaMask), BitCountAlpha, 8);

					Index++;
				}
			}
		}

		delete [] ColorTable;
		delete [] Line;

		file.close();
		return true;
	}
	
	bool Save(string Filename, unsigned int BitCount = 32)
	{
		char* charName = (char*) Filename.data();
		return Save(charName, BitCount);
	}
	bool Save(char* Filename, unsigned int BitCount = 32) {
		bool Result = false;

		std::ofstream file(Filename, std::ios::out | std::ios::binary);

		if (file.is_open() == false) {
			return false;
		}

		BITMAP_FILEHEADER bfh = {0};
		BITMAP_HEADER bh = {0};

		bfh.Signature = BITMAP_SIGNATURE;
		bfh.BitsOffset = BITMAP_FILEHEADER_SIZE + sizeof(BITMAP_HEADER);
		bfh.Size = (GetWidth() * GetHeight() * BitCount) / 8 + bfh.BitsOffset;

		bh.HeaderSize = sizeof(BITMAP_HEADER);
		bh.BitCount = BitCount;

		if (BitCount == 32) {
			bh.Compression = 3; // BITFIELD
			bh.AlphaMask = 0xff000000;
			bh.BlueMask = 0x00ff0000;
			bh.GreenMask = 0x0000ff00;
			bh.RedMask = 0x000000ff;
		} else if (BitCount == 16) {
			bh.Compression = 3; // BITFIELD
			bh.AlphaMask = 0x00000000;
			bh.BlueMask = 0x0000001f;
			bh.GreenMask = 0x000007E0;
			bh.RedMask = 0x0000F800;
		} else {
			bh.Compression = 0; // RGB
		}

		unsigned int LineWidth = (GetWidth() + 3) & ~3;

		bh.Planes = 1;
		bh.Height = GetHeight();
		bh.Width = GetWidth();
		bh.SizeImage = (LineWidth * BitCount * GetHeight()) / 8;
		bh.PelsPerMeterX = 3780;
		bh.PelsPerMeterY = 3780;

		if (BitCount == 32) {
			file.write((char*) &bfh, sizeof(BITMAP_FILEHEADER));
			file.write((char*) &bh, sizeof(BITMAP_HEADER));
			////IMPORTANT: I REMOVED THE FOLLOWING LINE AS IT WAS CREATING ERRORS> NOT SURE IF I WAS RIGHT
			file.write((char*) m_BitmapData, bh.SizeImage);
		} else if (BitCount < 16) {
			uint8_t* Bitmap = new uint8_t[bh.SizeImage];

			BGRA *Palette = 0;
			unsigned int PaletteSize = 0;

			if (GetBitsWithPalette(Bitmap, bh.SizeImage, BitCount, Palette, PaletteSize)) {
				bfh.BitsOffset += PaletteSize * sizeof(BGRA);

				file.write((char*) &bfh, BITMAP_FILEHEADER_SIZE);
				file.write((char*) &bh, sizeof(BITMAP_HEADER));
				file.write((char*) Palette, PaletteSize * sizeof(BGRA));
				file.write((char*) Bitmap, bh.SizeImage);
			}
			delete [] Bitmap;
			delete [] Palette;
		} else {
			uint32_t RedMask = 0;
			uint32_t GreenMask = 0;
			uint32_t BlueMask = 0;
			uint32_t AlphaMask = 0;

			if (BitCount == 16) {
				RedMask = 0x0000F800;
				GreenMask = 0x000007E0;
				BlueMask = 0x0000001F;
				AlphaMask = 0x00000000;
			} else if (BitCount == 24) {
				RedMask = 0x00FF0000;
				GreenMask = 0x0000FF00;
				BlueMask = 0x000000FF;
			} else {
				// Other color formats are not valid
				return false;
			}

			if (GetBits(NULL, bh.SizeImage, RedMask, GreenMask, BlueMask, AlphaMask)) {
				uint8_t* Bitmap = new uint8_t[bh.SizeImage];
				if (GetBits(Bitmap, bh.SizeImage, RedMask, GreenMask, BlueMask, AlphaMask)) {
					file.write((char*) &bfh, sizeof(BITMAP_FILEHEADER));
					file.write((char*) &bh, sizeof(BITMAP_HEADER));
					file.write((char*) Bitmap, bh.SizeImage);
				}
				delete [] Bitmap;
			}
		}
		Result = true;

		file.close();
		return Result;
	}

	unsigned int GetWidth() {
		return m_BitmapHeader.Width < 0 ? -m_BitmapHeader.Width : m_BitmapHeader.Width;
	}

	unsigned int GetHeight() {
		return m_BitmapHeader.Height < 0 ? -m_BitmapHeader.Height : m_BitmapHeader.Height;
	}

	unsigned int GetBitCount() {
		return m_BitmapHeader.BitCount;
	}

	/* Copies internal RGBA buffer to user specified buffer */

	bool GetBits(void* Buffer, unsigned int &Size) {
		bool Result = false;
		if (Size == 0 || Buffer == 0) {
			Size = m_BitmapSize * sizeof(RGBA);
			Result = m_BitmapSize != 0;
		} else {
			memcpy(Buffer, m_BitmapData, Size);
			Result = true;
		}
		return Result;
	}

	/* Returns internal RGBA buffer */

	void* GetBits() {
		return m_BitmapData;
	}

	/* Copies internal RGBA buffer to user specified buffer and converts it into destination
	 * bit format specified by component masks.
	 *
	 * Typical Bitmap color formats (BGR/BGRA):
	 *
	 * Masks for 16 bit (5-5-5): ALPHA = 0x00000000, RED = 0x00007C00, GREEN = 0x000003E0, BLUE = 0x0000001F
	 * Masks for 16 bit (5-6-5): ALPHA = 0x00000000, RED = 0x0000F800, GREEN = 0x000007E0, BLUE = 0x0000001F
	 * Masks for 24 bit: ALPHA = 0x00000000, RED = 0x00FF0000, GREEN = 0x0000FF00, BLUE = 0x000000FF
	 * Masks for 32 bit: ALPHA = 0xFF000000, RED = 0x00FF0000, GREEN = 0x0000FF00, BLUE = 0x000000FF
	 *
	 * Other color formats (RGB/RGBA):
	 *
	 * Masks for 32 bit (RGBA): ALPHA = 0xFF000000, RED = 0x000000FF, GREEN = 0x0000FF00, BLUE = 0x00FF0000
	 *
	 * Bit count will be rounded to next 8 bit boundary. If IncludePadding is true, it will be ensured
	 * that line width is a multiple of 4. padding bytes are included if necessary.
	 *
	 * NOTE: systems with big endian byte order may require masks in inversion order.
	 */

	bool GetBits(void* Buffer, unsigned int &Size, unsigned int RedMask, unsigned int GreenMask, unsigned int BlueMask, unsigned int AlphaMask, bool IncludePadding = true) {
		bool Result = false;

		uint32_t BitCountRed = CColor::BitCountByMask(RedMask);
		uint32_t BitCountGreen = CColor::BitCountByMask(GreenMask);
		uint32_t BitCountBlue = CColor::BitCountByMask(BlueMask);
		uint32_t BitCountAlpha = CColor::BitCountByMask(AlphaMask);

		unsigned int BitCount = (BitCountRed + BitCountGreen + BitCountBlue + BitCountAlpha + 7) & ~7;

		if (BitCount > 32) {
			return false;
		}

		unsigned int w = GetWidth();
		unsigned int LineWidth = (w + 3) & ~3;

		if (Size == 0 || Buffer == 0) {
			Size = (LineWidth * GetHeight() * BitCount) / 8 + sizeof(unsigned int);
			return true;
		}

		uint8_t* BufferPtr = (uint8_t*) Buffer;

		Result = true;

		uint32_t BitPosRed = CColor::BitPositionByMask(RedMask);
		uint32_t BitPosGreen = CColor::BitPositionByMask(GreenMask);
		uint32_t BitPosBlue = CColor::BitPositionByMask(BlueMask);
		uint32_t BitPosAlpha = CColor::BitPositionByMask(AlphaMask);

		unsigned int j = 0;

		for (unsigned int i = 0; i < m_BitmapSize; i++) {
			*(uint32_t*) BufferPtr =
			(CColor::Convert(m_BitmapData[i].Blue, 8, BitCountBlue) << BitPosBlue) |
			(CColor::Convert(m_BitmapData[i].Green, 8, BitCountGreen) << BitPosGreen) |
			(CColor::Convert(m_BitmapData[i].Red, 8, BitCountRed) << BitPosRed) |
			(CColor::Convert(m_BitmapData[i].Green, 8, BitCountAlpha) << BitPosAlpha);

			if (IncludePadding) {
				j++;
				if (j >= w) {
					for (unsigned int k = 0; k < LineWidth - w; k++) {
						BufferPtr += (BitCount >> 3);
					}
					j = 0;
				}
			}

			BufferPtr += (BitCount >> 3);
		}

		Size -= sizeof(unsigned int);

		return Result;
	}

	/* See GetBits().
	 * It creates a corresponding color table (palette) which have to be destroyed by the user after usage.
	 *
	 * Supported Bit depths are: 4, 8
	 *
	 * Todo: Optimize, use optimized palette, do ditehring (see my dithering class), support padding for 4 bit bitmaps
	 */

	bool GetBitsWithPalette(void* Buffer, unsigned int &Size, unsigned int BitCount, BGRA* &Palette, unsigned int &PaletteSize, bool OptimalPalette = false, bool IncludePadding = true) {
		bool Result = false;

		if (BitCount > 16) {
			return false;
		}

		unsigned int w = GetWidth();
		unsigned int LineWidth = (w + 3) & ~3;

		if (Size == 0 || Buffer == 0) {
			Size = (LineWidth * GetHeight() * BitCount) / 8;
			return true;
		}


		if (OptimalPalette) {
			PaletteSize = 0;
			// Not implemented
		} else {
			if (BitCount == 1) {
				PaletteSize = 2;
				// Not implemented: Who need that?
			} else if (BitCount == 4) { // 2:2:1
				PaletteSize = 16;
				Palette = new BGRA[PaletteSize];
				for (int r = 0; r < 4; r++) {
					for (int g = 0; g < 2; g++) {
						for (int b = 0; b < 2; b++) {
							Palette[r | g << 2 | b << 3].Red = r ? (r << 6) | 0x3f : 0;
							Palette[r | g << 2 | b << 3].Green = g ? (g << 7) | 0x7f : 0;
							Palette[r | g << 2 | b << 3].Blue = b ? (b << 7) | 0x7f : 0;
							Palette[r | g << 2 | b << 3].Alpha = 0xff;
						}
					}
				}
			} else if (BitCount == 8) { // 3:3:2
				PaletteSize = 256;
				Palette = new BGRA[PaletteSize];
				for (int r = 0; r < 8; r++) {
					for (int g = 0; g < 8; g++) {
						for (int b = 0; b < 4; b++) {
							Palette[r | g << 3 | b << 6].Red = r ? (r << 5) | 0x1f : 0;
							Palette[r | g << 3 | b << 6].Green = g ? (g << 5) | 0x1f : 0;
							Palette[r | g << 3 | b << 6].Blue = b ? (b << 6) | 0x3f : 0;
							Palette[r | g << 3 | b << 6].Alpha = 0xff;
						}
					}
				}
			} else if (BitCount == 16) { // 5:5:5
				// Not implemented
			}
		}

		unsigned int j = 0;
		uint8_t* BufferPtr = (uint8_t*) Buffer;

		for (unsigned int i = 0; i < m_BitmapSize; i++) {
			if (BitCount == 1) {
				// Not implemented: Who needs that?
			} else if (BitCount == 4) {
				*BufferPtr = ((m_BitmapData[i].Red >> 6) | (m_BitmapData[i].Green >> 7) << 2 | (m_BitmapData[i].Blue >> 7) << 3) << 4;
				i++;
				*BufferPtr |= (m_BitmapData[i].Red >> 6) | (m_BitmapData[i].Green >> 7) << 2 | (m_BitmapData[i].Blue >> 7) << 3;
			} else if (BitCount == 8) {
				*BufferPtr = (m_BitmapData[i].Red >> 5) | (m_BitmapData[i].Green >> 5) << 3 | (m_BitmapData[i].Blue >> 5) << 6;
			} else if (BitCount == 16) {
				// Not implemented
			}

			if (IncludePadding) {
				j++;
				if (j >= w) {
					for (unsigned int k = 0; k < (LineWidth - w); k++) {
						BufferPtr += BitCount / 8;
					}
					j = 0;
				}
			}

			BufferPtr++;
		}

		Result = true;

		return Result;
	}

	/* Set Bitmap Bits. Will be converted to RGBA internally */

	void SetBits(void* Buffer, unsigned int Width, unsigned int Height, unsigned int RedMask, unsigned int GreenMask, unsigned int BlueMask, unsigned int AlphaMask = 0) {
		uint8_t *BufferPtr = (uint8_t*) Buffer;

		Dispose();

		m_BitmapHeader.Width = Width;
		m_BitmapHeader.Height = Height;
		m_BitmapHeader.BitCount = 32;
		m_BitmapHeader.Compression = 3;

		m_BitmapSize = GetWidth() * GetHeight();
		m_BitmapData = new RGBA[m_BitmapSize];

		/* Find bit count by masks (rounded to next 8 bit boundary) */

		unsigned int BitCount = (CColor::BitCountByMask(RedMask | GreenMask | BlueMask | AlphaMask) + 7) & ~7;

		uint32_t BitCountRed = CColor::BitCountByMask(RedMask);
		uint32_t BitCountGreen = CColor::BitCountByMask(GreenMask);
		uint32_t BitCountBlue = CColor::BitCountByMask(BlueMask);
		uint32_t BitCountAlpha = CColor::BitCountByMask(AlphaMask);

		for (unsigned int i = 0; i < m_BitmapSize; i++) {
			unsigned int Color = 0;
			if (BitCount <= 8) {
				Color = *((uint8_t*) BufferPtr);
				BufferPtr += 1;
			} else if (BitCount <= 16) {
				Color = *((uint16_t*) BufferPtr);
				BufferPtr += 2;
			} else if (BitCount <= 24) {
				Color = *((uint32_t*) BufferPtr);
				BufferPtr += 3;
			} else if (BitCount <= 32) {
				Color = *((uint32_t*) BufferPtr);
				BufferPtr += 4;
			} else {
				/* unsupported */
				BufferPtr += 1;
			}
			m_BitmapData[i].Alpha = CColor::Convert(CColor::ComponentByMask(Color, AlphaMask), BitCountAlpha, 8);
			m_BitmapData[i].Red = CColor::Convert(CColor::ComponentByMask(Color, RedMask), BitCountRed, 8);
			m_BitmapData[i].Green = CColor::Convert(CColor::ComponentByMask(Color, GreenMask), BitCountGreen, 8);
			m_BitmapData[i].Blue = CColor::Convert(CColor::ComponentByMask(Color, BlueMask), BitCountBlue, 8);
		}
	}

	int redInRawArray (int index)
	{
		return (int) this->m_BitmapData[index].Red;
	}

	int greenInRawArray (int index)
	{
		return (int) this->m_BitmapData[index].Green;
	}

	int blueInRawArray (int index)
	{
		return (int) this->m_BitmapData[index].Blue;
	}

	int alphaInRawArray (int index)
	{
		return (int) this->m_BitmapData[index].Alpha;
	}

	void getRawArray (int index, int* myBuffer)
	{
		myBuffer[0] = (int) this->m_BitmapData[index].Red;
		myBuffer[1] = (int) this->m_BitmapData[index].Green;
		myBuffer[2] = (int) this->m_BitmapData[index].Blue;
		myBuffer[3] = (int) this->m_BitmapData[index].Alpha;
	}

	int redInXYPixel (int xx, int yy)
	{
		assert (yy < (int)this->GetHeight() && xx < (int)this->GetWidth());
		int index = yy * this->GetWidth() + xx;
		return (int) this->m_BitmapData[index].Red;
	}

	int greenInXYPixel (int xx, int yy)
	{
		assert (yy < (int)this->GetHeight() && xx < (int)this->GetWidth());
		int index = yy * this->GetWidth() + xx;
		return (int) this->m_BitmapData[index].Green;
	}

	int blueInXYPixel (int xx, int yy)
	{
		assert (yy < (int)this->GetHeight() && xx < (int)this->GetWidth());
		int index = yy * this->GetWidth() + xx;
		return (int) this->m_BitmapData[index].Blue;
	}

	int alphaInXYPixel (int xx, int yy)
	{
		assert (yy < (int)this->GetHeight() && xx < (int)this->GetWidth());
		int index = yy * this->GetWidth() + xx;
		return (int) this->m_BitmapData[index].Alpha;
	}

	/**
	 * Copies the R, G and B values of a pixel to the given array.
	 */
	void getXYRGB (int xx, int yy, int* myBuffer)
	{
		int index = yy * this->GetWidth() + xx;
		myBuffer[0] = (int) this->m_BitmapData[index].Red;
		myBuffer[1] = (int) this->m_BitmapData[index].Green;
		myBuffer[2] = (int) this->m_BitmapData[index].Blue;
	}

	bool isWhiteXY (int xx, int yy)
	{
		int index = yy * this->GetWidth() + xx;
		return (this->m_BitmapData[index].Red == 255 && this->m_BitmapData[index].Green == 255
			&& this->m_BitmapData[index].Blue == 255);
	}

	bool isBlackXY (int xx, int yy)
	{
		int index = yy * this->GetWidth() + xx;
		return (this->m_BitmapData[index].Red == 0 && this->m_BitmapData[index].Green == 0
			&& this->m_BitmapData[index].Blue == 0);
	}

	void setWhiteXY (int xx, int yy)
	{
		int index = yy * this->GetWidth() + xx;
		this->m_BitmapData[index].Red = 255;
		this->m_BitmapData[index].Green = 255;
		this->m_BitmapData[index].Blue = 255;
	}

	void setBlackXY (int xx, int yy)
	{
		int index = yy * this->GetWidth() + xx;
		this->m_BitmapData[index].Red = 0;
		this->m_BitmapData[index].Green = 0;
		this->m_BitmapData[index].Blue = 0;
	}

	//------------------------------------------


	int redInRCPixel (int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		return (int) this->m_BitmapData[index].Red;
	}

	int greenInRCPixel (int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		return (int) this->m_BitmapData[index].Green;
	}

	int blueInRCPixel (int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		return (int) this->m_BitmapData[index].Blue;
	}

	int alphaInRCPixel (int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		return (int) this->m_BitmapData[index].Alpha;
	}

	/** Returns the intensity of the given component of the given pixel. */
	int getIntensity (int row, int col, string component = "average")
	{
		assert ( (component=="average" || component=="red" || component=="green" || component=="blue") && "The only valid values for the component are average, red, green and blue."
			&& "All lower case.");
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		if (component == "red")
			return redInRCPixel (row, col);
		else if (component == "green")
			return greenInRCPixel (row, col);
		else if (component == "blue")
			return blueInRCPixel (row, col);
		else
		{
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		return (int) ((this->m_BitmapData[index].Red + this->m_BitmapData[index].Green + this->m_BitmapData[index].Blue)/3);
		}
	}

	/**
	 * Copies the R, G and B values of a pixel to the given array.
	 */
	void getRCRGB (int row, int col, int* myBuffer)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		myBuffer[0] = (int) this->m_BitmapData[index].Red;
		myBuffer[1] = (int) this->m_BitmapData[index].Green;
		myBuffer[2] = (int) this->m_BitmapData[index].Blue;
	}

	bool isWhiteRC (int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		return (this->m_BitmapData[index].Red == 255 && this->m_BitmapData[index].Green == 255
			&& this->m_BitmapData[index].Blue == 255);
	}

	bool isBlackRC (int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		return (this->m_BitmapData[index].Red == 0 && this->m_BitmapData[index].Green == 0
			&& this->m_BitmapData[index].Blue == 0);
	}

	void setWhiteRC (int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		this->m_BitmapData[index].Red = 255;
		this->m_BitmapData[index].Green = 255;
		this->m_BitmapData[index].Blue = 255;
	}

	void setBlackRC (int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		this->m_BitmapData[index].Red = 0;
		this->m_BitmapData[index].Green = 0;
		this->m_BitmapData[index].Blue = 0;
	}

	/** Sets the color of the pixel whose r and c is given to the gray whose intensity is given in value. */
	void setGrayRC (int value, int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		//int oneThird = value/3;
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		this->m_BitmapData[index].Red = value; //oneThird;
		this->m_BitmapData[index].Green = value;//oneThird;
		this->m_BitmapData[index].Blue = value;//oneThird;
		this->m_BitmapData[index].Alpha = 0;//oneThird;
	}

	/** Sets the green component of the given pixel to the given value, resets the other components to zero. */
	void setGreenRC (int value, int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		this->m_BitmapData[index].Red = 0; //oneThird;
		this->m_BitmapData[index].Green = value;//oneThird;
		this->m_BitmapData[index].Blue = 0;//oneThird;
		this->m_BitmapData[index].Alpha = 0;//oneThird;
	}

		/** Sets the red component of the given pixel to the given value, resets the other components to zero. */
	void setRedRC (int value, int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		this->m_BitmapData[index].Red = value; //oneThird;
		this->m_BitmapData[index].Green = 0;//oneThird;
		this->m_BitmapData[index].Blue = 0;//oneThird;
		this->m_BitmapData[index].Alpha = 0;//oneThird;
	}

	/** Sets the blue component of the given pixel to the given value, resets the other components to zero. */
	void setBlueRC (int value, int row, int col)
	{
		assert (row < (int)this->GetHeight() && col < (int)this->GetWidth());
		row = this->GetHeight() - 1 - row;
		int index = row * this->GetWidth() + col;
		this->m_BitmapData[index].Red = 0; //oneThird;
		this->m_BitmapData[index].Green = 0;//oneThird;
		this->m_BitmapData[index].Blue = value;//oneThird;
		this->m_BitmapData[index].Alpha = 0;//oneThird;
	}

	/** saves the current object n times (n=copyNum) with the given file name (basename+0,1,2....bmp) */
	void makeCopies (string baseName, int copyNum = 1, int bitCount = 32U)
	{
		string fName;// = new string[copyNum];// = new string[copyNum];
		//char myBuff[2];
		for (int i = 0; i < copyNum; i++)
		{
			fName = baseName + int2Str(i) /*_itoa(i,myBuff,10)*/ + ".bmp";
			Save(fName, bitCount);
		}
	}

	/** Creates all-white bmp files with the same size as the current CBitmap object. 
	 * \param blankName the base name (with no extention) of the copy file.
	 * \param copyNum the number of copies.
	 * e.g. if (myfile, 2) is given, two all-white bmp files with the same size as the 
	 * current object will be created. The names will be myfile0.bmp and myfile1.bmp
	 */
	void makeWhiteCopies (string blankName, int copyNum = 1, int bitCount = 32U)
	{
		this->Save("deletethis.bmp", bitCount);
		CBitmap tempWhite("deletethis.bmp");
		int rowNum = tempWhite.GetHeight();
		int colNum = tempWhite.GetWidth();
		for (int row = 0; row < rowNum; row++)
			for (int col = 0; col < colNum; col++)
				tempWhite.setWhiteRC(row,col);
		//tempWhite.Save("deletethis.bmp");
		string fName;// = new string[copyNum];// = new string[copyNum];
		//char myBuff[2];
		for (int i = 0; i < copyNum; i++)
		{
			fName = blankName + int2Str(i) /*_itoa(i,myBuff,10)*/ + ".bmp";
			tempWhite.Save(fName, bitCount);
		}
	}

	/**
	 * This function divides the image into 'layers' number of images, where each image is only black and white (mono color)
	 * and keeps the value of the bit in the 'layers' position. For example, ("myfile", "bmp", 2) creates 2 images myfile0.bmp
	 * and myfile1.bmp, where each pixel in myfile0.bmp shows the most significant bit of the corresponding pixel in myfile.bmp
	 * and each pixel in myfile1.bmp shows the next significant bit of the corresponding pixel in myfile.bmp.
	 */
	void separateBits (string targetName, string type = "bmp", int layers = 8)
	{
		assert ( (type=="bmp" || type=="txt") && "the only valid types are bmp and txt, all lower case.");
		int pValue; //intensity value of the pixel.
		//char myBuff[2];
		int rowNum = this->GetHeight();
		int colNum = this->GetWidth();
		if (type == "bmp")
		{
			makeCopies (targetName, layers);
			CBitmap** layerImage = new CBitmap*[layers];
			for (int l = 0; l < layers; l++)
				layerImage[l] = new CBitmap(targetName + int2Str(l) /*_itoa(l, myBuff,10)*/ + ".bmp");

			for (int r = 0; r < rowNum; r++)
				for (int c = 0; c < colNum; c++)
				{
					pValue = getIntensity (r, c, "average");
					for (int l = 0; l < layers; l++)
					{
						//layerImages[l]->Load(targetName + _itoa(i, myBuff,10) + ".bmp");
						
						if (pValue >= (int) pow((double)2, layers-1-l)) //is the bit for this layer "1"?
						{
							layerImage[l]->setWhiteRC(r,c);
							pValue -= (int)pow((double)2,layers-1-l);
						}
						else
							layerImage[l]->setBlackRC(r,c);
					}
				}
			for (int l = 0; l < layers; l++)
			{
				layerImage[l]->Save(targetName + int2Str(l) /*_itoa(l, myBuff,10)*/ + ".bmp");
				delete layerImage[l];
			}
			delete[] layerImage;
		}
		else 
		{
			ofstream** outputTextFile = new ofstream*[layers];
			//char myBuff[2];
			for (int l = 0; l < layers; l++)
			{
				outputTextFile[l] = new ofstream;
				std::string fileName(targetName+ int2Str(l) + ".txt");
				const char* fileNameCharP = fileName.data();
				outputTextFile[l]->open(fileNameCharP);
				outputTextFile[l]->clear();
			}

			//int r,b,g,a;
			//double intensity;
			for (int row = 0; row < rowNum; row++)
			{
				for (int col = 0; col < colNum; col++)
				{
					pValue = getIntensity (row, col, "average");
					for (int l = 0; l < layers; l++)
					{
						//layerImages[l]->Load(targetName + _itoa(i, myBuff,10) + ".bmp");
						
						if (pValue >= (int) pow((double)2, layers-1-l)) //is the bit for this layer "1"?
						{
							*outputTextFile[l] << 0 << "\t";
							pValue -= (int)pow((double)2,layers-1-l);
						}
						else
							*outputTextFile[l] << 1 << "\t";
					}
				}
				for (int l = 0; l < layers; l++)
					*outputTextFile[l] << endl;
			}
		//TODO: Write separate image for txt files.
		}

	}
					



};

#endif
